package main

import "fmt"

func main() {
	definedSlice()
	appendSlice()
	copyAndDeleteSlice()
}

func definedSlice() {
	//定义slice, slice的零值是nil
	//Zero value for slice is nil
	var emptySlice []int
	fmt.Println("emptySlice is equal to nil = ", emptySlice == nil)
	printSlice("emptySlice", emptySlice)

	//仅指定数组长度, 那么容量默认为数组长度
	defSlice1 := make([]int, 16)
	//同时指定slice的长度和容量
	defSlice2 := make([]int, 16, 32)
	printSlice("defSlice1", defSlice1)
	printSlice("defSlice2", defSlice2)
	fmt.Println()

	//数组(... 不定长度)
	arr := [...]int{0, 1, 2, 3}
	//切片, 像是数组(arr)的一个视图(view)
	printSlice("arr[1:3]", arr[1:3])
	printSlice("arr[:3]", arr[:3])
	fmt.Println("arr[1:3] =", arr[1:3])
	fmt.Println("arr[ :3] =", arr[:3])
	fmt.Println("arr[1: ] =", arr[1:])
	fmt.Println("arr[ : ] =", arr[:])

	fmt.Println()

	s1 := arr[1:3]
	s2 := arr[:]
	fmt.Println("s1=", s1)
	fmt.Println("s2=", s2)
	//发现实际更新的是从slice下标为0开始计算的数
	//并且会同步更新源arr的数据(arr[1])
	updateSlice(s1, 0)
	fmt.Println("after update slice")
	fmt.Println("after update slice")
	fmt.Println("s1=", s1)
	fmt.Println("s2=", s2)

	fmt.Println()
	//对slice再进行切片
	fmt.Println("re slice")

	//s1只有[0,2)下标, 理论上不能取到3下标, 但是数组中有下标3, 就能取到, 不过不能超过数组下标
	//特点: slice可以向后扩展, 但是不可以向前扩展
	// slice的下标(index), s[idx]不可以超过底层数组的长度( len(array) )
	fmt.Println("s3=", s1[1:3])
	fmt.Println("definedSlice end...")
	fmt.Println()

}

func updateSlice(s []int, idx int) {
	s[idx] = -1
}

func appendSlice() {
	arr := [...]int{0, 1, 2, 3}
	s1 := arr[1:3]
	fmt.Println("s1=", s1, "\t arr=", arr)
	//数组在 idx=3 的位置还有值, 会直接修改对应值
	s2 := append(s1, 11)
	fmt.Println("s2=", s2, "\t arr=", arr)
	//这里已经超过数组下标范围了, 继续追加不会修改原数组(会生成新的扩容数组, slice再对新的数组进行view, 和之前的arr就没有关联了)
	//原arr如果还有其他引用, 则会继续留存, 否则会被垃圾回收
	s3 := append(s2, 12)
	fmt.Println("s3=", s3, "\t arr=", arr)
	fmt.Println("appendSlice end...")
	fmt.Println()
}

func printSlice(name string, s []int) {
	fmt.Printf("sliceName=%s len=%d, cap=%d\n", name, len(s), cap(s))
}

func copyAndDeleteSlice() {
	s1 := []int{2, 4, 6, 8}
	s2 := make([]int, 16)
	s3 := make([]int, 10, 32)
	copy(s2, s1)
	fmt.Println("after copy s2=", s2)
	//删除下标(idx)=3的元素, 原理是把源slice的需要留下的元素挑出来, 拼接成新的slice
	s2 = append(s2[:3], s2[4:]...)
	//会发现len减少了1, 而cap保持不变
	fmt.Println("after del  s2=", s2)

	//从头部弹出
	front := s2[0]
	s2 = s2[1:]
	fmt.Println("after pop  s2=", s2, " front=", front)

	//从尾部弹出
	tail := s2[len(s2)-1]
	s2 = s2[:len(s2)-1]
	fmt.Println("after pop  s2=", s2, "  tail=", tail)

	fmt.Println("after del  s3=", s3)
}
